#include "frame_util.h"

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis/hiredis.h>
#include "data_type.h"
#include "redis_util.h"

extern uint8_t *sn;

/**
 * @brief 查找数据包里面的结束字符位置
 * 
 * @param str 原始数据缓冲区
 * @param c 结束字符
 * @param len 原始数据长度
 * @return uint8_t* 找到字符后返回其后部分（包括结尾的空字符）
 */
uint8_t* find_substring(uint8_t *str, uint8_t c, uint16_t len) {
    int i = 0;
    if (str == NULL) {
        return NULL;
    }
    // 遍历字符串直到找到目标字符或到达结尾
    printf("FindSub:");
    while (i < len) {
        printf("%02X ", *(str + i));
        if (i > 0 && (*(str + i -1)<<8 | *(str+i)) == 0xA5A3) {
            i++;
        } else if(i > 0 && i < (len-1) && ((*(str+i-1)<<8 | *(str+i)) == 0xA3A3 || (*(str + i)<<8 | *(str+i+1)) == 0xA3A3)){
            i = i+2;
        } else if(*(str + i) == c) {
            break;
        } else {
            i++;
        }
    }
    printf("\n");
    // 找到字符后返回其后部分（包括结尾的空字符）
    return (*(str+i) == c) ? str + i : NULL;
}

/**
 * @brief 对16进制数组进行转义编码
 * @param data 输入数据数组
 * @param len 输入数据长度
 * @param out_len 输出数据长度的指针
 * @return uint8_t* 转义后的数组指针，需要调用者释放内存
 */
uint8_t* escape_data(const uint8_t* data, int len, int* out_len) {
    // 检查输入有效性
    if (len < 2 || (data[0] != 0xA5 && data[0] != 0xA6) || data[len-1] != 0xA3) {
        *out_len = 0;
        return NULL;
    }
    
    // 分配临时缓冲区（最坏情况：每个字节都需要转义）
    uint8_t* temp_buffer = (uint8_t*)malloc(len * 2);
    if (!temp_buffer) return NULL;
    
    int j = 0;
    
    // 添加起始字节
    temp_buffer[j++] = data[0];
    
    // 处理中间数据（从第二个字节到倒数第二个字节）
    for (int i = 1; i < len - 1; i++) {
        if (data[i] == 0xA5) {
            // A5开头时，A5转义为A5A3
            temp_buffer[j++] = 0xA5;
            temp_buffer[j++] = 0xA3;
        } else if (data[i] == 0xA6) {
            // A6开头时，A6转义为A6A3
            temp_buffer[j++] = 0xA6;
            temp_buffer[j++] = 0xA3;
        } else if (data[i] == 0xA3) {
            // A3转义为A3A3
            temp_buffer[j++] = 0xA3;
            temp_buffer[j++] = 0xA3;
        } else {
            // 普通字节直接复制
            temp_buffer[j++] = data[i];
        }
    }
    
    // 添加结束字节A3
    temp_buffer[j++] = 0xA3;
    
    // 分配精确大小的内存并返回
    uint8_t* result = (uint8_t*)malloc(j);
    if (result) {
        memcpy(result, temp_buffer, j);
        *out_len = j;
    }
    
    free(temp_buffer);
    return result;
}

/**
 * @brief 对转义后的16进制数组进行解码
 * @param escaped_data 转义后的数据数组
 * @param len 转义数据长度
 * @param out_len 输出数据长度的指针
 * @return uint8_t* 解码后的原始数组指针，需要调用者释放内存
 */
uint8_t* unescape_data(const uint8_t* escaped_data, int len, int* out_len) {
    // 检查输入有效性
    if (len < 2 || (escaped_data[0] != 0xA5 && escaped_data[0] != 0xA6) || escaped_data[len-1] != 0xA3) {
        *out_len = 0;
        return NULL;
    }
    
    // 分配临时缓冲区
    uint8_t* temp_buffer = (uint8_t*)malloc(len);
    if (!temp_buffer) return NULL;
    
    int j = 0;
    temp_buffer[j++] = escaped_data[0]; // 添加起始字节
    
    // 遍历处理中间数据（跳过起始字节和结束字节）
    for (int i = 1; i < len - 1; i++) {
        if (i < len - 1) {
            if (escaped_data[i] == 0xA5 && escaped_data[i+1] == 0xA3) {
                // A5开头时，A5A3反转义为A5
                temp_buffer[j++] = 0xA5;
                i++; // 跳过下一个A3字节
            } else if (escaped_data[i] == 0xA6 && escaped_data[i+1] == 0xA3) {
                // A6开头时，A6A3反转义为A6
                temp_buffer[j++] = 0xA6;
                i++; // 跳过下一个A3字节
            } else if (escaped_data[i] == 0xA3 && escaped_data[i+1] == 0xA3) {
                // A3A3反转义为A3
                temp_buffer[j++] = 0xA3;
                i++; // 跳过下一个A3字节
            } else {
                // 普通字节直接复制
                temp_buffer[j++] = escaped_data[i];
            }
        } else {
            // 最后一个字节前的情况
            temp_buffer[j++] = escaped_data[i];
        }
    }
    
    // 添加结束字节
    temp_buffer[j++] = 0xA3;
    
    // 分配精确大小的内存
    uint8_t* result = (uint8_t*)malloc(j);
    if (result) {
        memcpy(result, temp_buffer, j);
        *out_len = j;
    }
    
    free(temp_buffer);
    return result;
}
/**
 * @brief 解析数据帧，把解决装到结构体数据里面
 * 
 * @param input 需要解析的数据帧
 * @param length 解析的数据长度
 * @return t_FrameData 解析后的结构体数据
 */
t_FrameData * parse_frame(uint8_t *input, uint16_t length){
    if (length < 7){
        return NULL;
    }
    int out_len;
    uint8_t * output = unescape_data(input, length, &out_len);
    if(output){
        uint16_t calc_crc = rtu_crc((uint8_t*)output, out_len - 3);
        uint16_t crc = output[out_len -3] << 8 | output[out_len-2];
        if(calc_crc == crc) {
            t_FrameData *frame = (t_FrameData *) malloc(sizeof(t_FrameData));

            frame->start = output[0];
            frame->type = input[1];
            frame->len = input[2]<<8 | input[3];
            frame->crc = crc;
            frame->end = output[out_len -1];
            memcpy(frame->data, output+4, out_len - 7);
            free(output);
            return frame;
        }
        free(output);
    }
    return NULL;
}
/**
 * @brief 把结构体数据帧转化为数据帧
 * 
 * @param t_FrameData 需要解析的数据帧
 * @param out_len 解析的数据长度
 * @return 返回结果数据帧，调用者使用后，需要释放内存
 */
uint8_t * unparse_frame(t_FrameData *frame, int *out_len){
    uint8_t *temp_buf = (uint8_t *)malloc(frame->len + 7);
    *temp_buf = frame->start;
    *(temp_buf+1) = frame->type;
    *(temp_buf+2) = ((frame->len > 8) & 0xFF);
    *(temp_buf+3) = (frame->len & 0xFF);
    memcpy(temp_buf + 4, frame->data, frame->len);
    uint16_t calc_crc = rtu_crc(temp_buf, frame->len + 4);
    *(temp_buf + frame->len + 4) = ((calc_crc > 8) & 0xFF);
    *(temp_buf + frame->len + 5) = (calc_crc & 0xFF);
    *(temp_buf + frame->len + 6) = frame->end;
    uint8_t *output = escape_data(temp_buf, frame->len + 7, out_len);
    free(temp_buf);
    return output;
}

/**
 * @brief 解析电源系统状态数据，并把数据组装为JSON格式存放到Redis中
 * 
 * @param data 需要解析的数据帧
 */
char *parse_mppt(LoraData data){
    uint8_t *bRecvBuf = data.data;
    uint8_t device_sn[50]={0}, modelNumber[50]={0};
    uint8_t key[4]={0};
    StEnergyInfo energyAck;
    cJSON *root = cJSON_CreateObject();
    printf("1\n");
    sprintf(key, "%04X", data.dev_num);
    printf("key:%s\n", key);
    int res = redis_pull_data("config_devs", key, device_sn);
    if(res == -1) return NULL;
    printf("key1:%s\n", key);
    if(device_sn == NULL) return NULL;
    printf("sn:%s\n", device_sn);
    EP_JSON_SET_STR(root, "sn", device_sn);
    EP_JSON_SET_INT(root, "dataType", 5);
    EP_JSON_SET_INT(root, "version", 1);

    cJSON *enertyData = cJSON_CreateObject();
    sprintf(modelNumber, "%sDY1", device_sn);
    EP_JSON_SET_STR(enertyData, "modelNumber", modelNumber);
    cJSON *statusData = cJSON_CreateObject();
    /**
     * 解析电源模块当前状态
     */
    energyAck.powerStatus = *bRecvBuf;
    EP_JSON_SET_INT(statusData, "powerStatus", energyAck.powerStatus);
    printf("模块状态:%d\n", energyAck.powerStatus);
    energyAck.offTime = ((*(bRecvBuf+1) << 8) + *(bRecvBuf+2));
    EP_JSON_SET_INT(statusData, "offTime", energyAck.offTime);
    printf("休眠时长:%dm\n", energyAck.offTime);
    energyAck.onTime = ((*(bRecvBuf+3) << 8) + *(bRecvBuf+4));
    EP_JSON_SET_INT(statusData, "onTime", energyAck.onTime);
    printf("唤醒时长:%dm\n", energyAck.onTime);
    cJSON_AddItemToObject(enertyData,"statusData",statusData);
   
    /**
     * 解析电源模块电量信息
     */
    cJSON *powerData = cJSON_CreateObject();
    energyAck.batteryVoltage = (float)((*(bRecvBuf+5) << 8) + *(bRecvBuf+6))/100;
    EP_JSON_SET_INT(powerData, "batteryVoltage", energyAck.batteryVoltage);
    printf("电池电压:%f\n", energyAck.batteryVoltage);
    energyAck.batteryElectric = (float)((*(bRecvBuf+7)<<8) + *(bRecvBuf+8))/1000;
    EP_JSON_SET_INT(powerData, "batteryElectric", energyAck.batteryElectric);
    printf("电池电流:%f\n", energyAck.batteryElectric);
    energyAck.batteryCapacity =  *(bRecvBuf+9);
    EP_JSON_SET_INT(powerData, "batteryCapacity", energyAck.batteryCapacity);
    printf("电池余量:%d\n", energyAck.batteryCapacity);
    energyAck.batteryStatus = *(bRecvBuf+5);
    EP_JSON_SET_INT(powerData, "batteryStatus", energyAck.batteryStatus);
    printf("电池状态:%d\n", energyAck.batteryStatus);

    energyAck.loadVoltage = (float)((*(bRecvBuf+11)<<8) + *(bRecvBuf+12))/100;
    EP_JSON_SET_INT(powerData, "loadVoltage", energyAck.loadVoltage);
    printf("负载电压:%f\n", energyAck.loadVoltage);
    energyAck.loadElectric = (float)((*(bRecvBuf+13)<<8) + *(bRecvBuf+14))/1000;
    EP_JSON_SET_INT(powerData, "loadElectric", energyAck.loadElectric);
    printf("负载电流:%f\n", energyAck.loadElectric);
    energyAck.loadPower = (float)((*(bRecvBuf+15)<<8) + *(bRecvBuf+16))/100;
    EP_JSON_SET_INT(powerData, "loadPower", energyAck.loadPower);
    printf("负载功率:%f\n", energyAck.loadPower);
    energyAck.loadStatus = *(bRecvBuf+17);
    EP_JSON_SET_INT(powerData, "loadStatus", energyAck.loadStatus);
    printf("负载状态:%d\n", energyAck.loadStatus);

    energyAck.columnVoltage = (float)((*(bRecvBuf+18)<<8) + *(bRecvBuf+19))/100;
    EP_JSON_SET_INT(powerData, "columnVoltage", energyAck.columnVoltage);
    printf("阵列电压:%f\n", energyAck.columnVoltage);
    energyAck.columnStatus = *(bRecvBuf+20);
    EP_JSON_SET_INT(powerData, "columnStatus", energyAck.columnStatus);
    printf("阵列状态:%d\n", energyAck.columnStatus);

    energyAck.runDay = (*(bRecvBuf+21)<<8) + *(bRecvBuf+22);
    EP_JSON_SET_INT(powerData, "runDay", energyAck.runDay);
    printf("运行天数:%d\n", energyAck.runDay);
    energyAck.lowVolCnt = (*(bRecvBuf+23)<<8) + *(bRecvBuf+24);
    EP_JSON_SET_INT(powerData, "lowVolCnt", energyAck.lowVolCnt);
    printf("欠压次数:%d\n", energyAck.lowVolCnt);
    energyAck.todayDischarge = (*(bRecvBuf+25)<<8) + *(bRecvBuf+26);
    EP_JSON_SET_INT(powerData, "todayDischarge", energyAck.todayDischarge);
    printf("今日总放电量:%d\n", energyAck.todayDischarge);
    energyAck.yesterdayDischarge = (*(bRecvBuf+27)<<8) + *(bRecvBuf+28);
    EP_JSON_SET_INT(powerData, "yesterdayDischarge", energyAck.yesterdayDischarge);
    printf("昨日总放电量:%d\n", energyAck.yesterdayDischarge);
    energyAck.totalDischarge = (*(bRecvBuf+29)<<32) + (*(bRecvBuf+30)<<16) + (*(bRecvBuf+31)<<8) + *(bRecvBuf+32);
    EP_JSON_SET_INT(powerData, "totalDischarge", energyAck.totalDischarge);
    printf("累计总放电量:%ld\n", energyAck.totalDischarge);
    energyAck.todayCharge = (*(bRecvBuf+33)<<8) + *(bRecvBuf+34);
    EP_JSON_SET_INT(powerData, "todayCharge", energyAck.todayCharge);
    printf("今日总充电量:%d\n", energyAck.todayCharge);
    energyAck.yesterdayCharge = (*(bRecvBuf+35)<<8) + *(bRecvBuf+36);
    EP_JSON_SET_INT(powerData, "yesterdayCharge", energyAck.yesterdayCharge);
    printf("昨日总充电量:%d\n", energyAck.yesterdayCharge);
    energyAck.totalCharge = (*(bRecvBuf+32)<<37) + (*(bRecvBuf+38)<<16) + (*(bRecvBuf+39)<<8) + *(bRecvBuf+40);
    EP_JSON_SET_INT(powerData, "totalCharge", energyAck.totalCharge);
    printf("累计总充电量:%ld\n", energyAck.totalCharge);
    energyAck.fDevTemperature = (float)((*(bRecvBuf+41)<<8) + *(bRecvBuf+42))/10;
    EP_JSON_SET_INT(powerData, "fDevTemperature", energyAck.fDevTemperature);
    printf("控制器内部温度:%f\n", energyAck.fDevTemperature);
    energyAck.fBatTemperature = (float)((*(bRecvBuf+43)<<8) + *(bRecvBuf+44))/10;
    EP_JSON_SET_INT(powerData, "fBatTemperature", energyAck.fBatTemperature);
    printf("控制器外部温度:%f\n", energyAck.fBatTemperature);

    cJSON_AddItemToObject(enertyData,"powerData",powerData);
    cJSON_AddItemToObject(root,"data",enertyData);
    char *str = cJSON_Print(root);

    uint8_t num[4];
    sprintf(num, "%04X", data.dev_num);
    redis_push_data("devlist",num, str);

    cJSON_Delete(root);
    return str;
}
